home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume90 / util / snap_1_4 / part03 < prev    next >
Internet Message Format  |  1990-02-11  |  59KB

  1. Path: xanth!cs.odu.edu!Amiga-Request
  2. From: Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v90i069: Snap 1.4 - cut, store, and paste between windows, Part03/04
  5. Message-ID: <11377@xanth.cs.odu.edu>
  6. Date: 11 Feb 90 22:51:09 GMT
  7. Sender: tadguy@cs.odu.edu
  8. Reply-To: micke@slaka.sirius.se (Mikael Karlsson)
  9. Lines: 1836
  10. Approved: tadguy@cs.odu.edu (Tad Guy)
  11. X-Mail-Submissions-To: Amiga@cs.odu.edu
  12. X-Post-Discussions-To: comp.sys.amiga
  13.  
  14. Submitted-by: micke@slaka.sirius.se (Mikael Karlsson)
  15. Posting-number: Volume 90, Issue 069
  16. Archive-name: util/snap-1.4/part03
  17.  
  18. #!/bin/sh
  19. # This is a shell archive.  Remove anything before this line, then unpack
  20. # it by saving it into a file and typing "sh file".  To overwrite existing
  21. # files, type "sh file -c".  You can also feed this as standard input via
  22. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  23. # will see the following message at the end:
  24. #        "End of archive 3 (of 4)."
  25. # Contents:  source/handler.s source/minrexx.c source/snapchars.c
  26. # Wrapped by tadguy@xanth on Sun Feb 11 17:48:46 1990
  27. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  28. if test -f 'source/handler.s' -a "${1}" != "-c" ; then 
  29.   echo shar: Will not clobber existing file \"'source/handler.s'\"
  30. else
  31. echo shar: Extracting \"'source/handler.s'\" \(17796 characters\)
  32. sed "s/^X//" >'source/handler.s' <<'END_OF_FILE'
  33. X        include "exec/types.i"
  34. X        include "exec/lists.i"
  35. X        include "devices/inputevent.i"
  36. X
  37. Xwaiting   equ 0
  38. Xselregion equ 1
  39. Xwaitext   equ 2
  40. Xselgfx    equ 3
  41. Xwaitgfx   equ 4
  42. Xinserting equ 5
  43. Xpendsnap  equ 6
  44. Xkillbutt  equ 7
  45. X
  46. Xnoaction  equ 0
  47. Xsnapgfx   equ 1
  48. Xsnaptext  equ 2
  49. Xsnapinit  equ 3
  50. Xinsert    equ 4
  51. Xcancel    equ 5
  52. X
  53. XLMB       equ IECODE_LBUTTON
  54. XLMB_UP    equ IECODE_UP_PREFIX+IECODE_LBUTTON
  55. XRMB       equ IECODE_RBUTTON
  56. XRMB_UP    equ IECODE_UP_PREFIX+IECODE_RBUTTON
  57. XNO_BUTT   equ IECODE_NOBUTTON
  58. XLCOM      equ IEQUALIFIER_LCOMMAND
  59. XSHIFT     equ IEQUALIFIER_LSHIFT+IEQUALIFIER_RSHIFT
  60. X
  61. X
  62. X        XDEF    _myhandler
  63. X        XREF    _geta4
  64. X        XREF    _LVOSignal
  65. X        XREF    _SysBase
  66. X        XREF    _MyTask
  67. X        XREF    _action
  68. X        XREF    _state
  69. X        XREF    _modinsert
  70. X        XREF    _startsignal
  71. X        XREF    _insertsignal
  72. X        XREF    _cancelsignal
  73. X        XREF    _donesignal
  74. X        XREF    _movesignal
  75. X        XREF    _clicksignal
  76. X        XREF    _timersignal
  77. X        XREF    _initsignal
  78. X        XREF    _cwsignal
  79. X        XREF    _textqual                      ; qualifier for snapping text
  80. X        XREF    _gfxqual                       ;    -"-    -"-   -"-    gfx
  81. X        XREF    _insertkey
  82. X        XREF    _cwkey
  83. X
  84. X        SECTION CODE
  85. X
  86. X_myhandler:
  87. X
  88. X; On entry: a0 : Pointer to event list
  89. X;           a1 : Pointer to data
  90. X
  91. X; In loop:  a1 : Pointer to event
  92. X;           d0 : scratch
  93. X
  94. X; Result:   d0 : New event list
  95. X
  96. X        movem.l a4,-(sp)
  97. X
  98. X        jsr     _geta4                         ; Get offset base a4
  99. X
  100. X        move.l  a0,a1                          ; a1 = Event list = a0
  101. X
  102. X.nextevent
  103. X        cmpa.l  #0,a1                          ; Check for end of list
  104. X        beq     .done
  105. X
  106. X        cmp.w   #noaction,_action              ; forced noaction - cancel
  107. X        bne     .notcanceled                   ; no, we're in action
  108. X        move.w  #waiting,_state                ; no action -> wait state
  109. X        bra     .dostate
  110. X.notcanceled
  111. X        cmp.w   #insert,_action                ; forced insert - cancel
  112. X        bne     .dostate                       ; no
  113. X        move.w  #inserting,_state              ; set correct state
  114. X
  115. X.dostate
  116. X        move.w  _state,d0
  117. X        asl.w   #1,d0
  118. X        move.w  JumpTable(pc,d0.w),d0
  119. XOrigin
  120. X        jmp     0(pc,d0.w)
  121. XJumpTable
  122. X        dc.w    .Waiting-Origin-2
  123. X        dc.w    .SelRegion-Origin-2
  124. X        dc.w    .WaitExt-Origin-2
  125. X        dc.w    .SelGfx-Origin-2
  126. X        dc.w    .WaitGfx-Origin-2
  127. X        dc.w    .Insert-Origin-2
  128. X        dc.w    .PendSnap-Origin-2
  129. X        dc.w    .CancelTxt-Origin-2
  130. X
  131. X; ********************************************************
  132. X; State: Waiting    ~TQ
  133. X; Actions     New state             Signal
  134. X; TQ          PendSnap              init
  135. X; LMB+GQ      SelGfx                init+start
  136. X; LCOM+IKEY   Inserting             insert
  137. X
  138. X.Waiting
  139. X        cmp.b   #IECLASS_RAWKEY,ie_Class(a1)   ; Is it RAWKEY?
  140. X        bne     .wait_RAWMOUSE
  141. X
  142. X        move.w  ie_Qualifier(a1),d0
  143. X        and.w   _textqual,d0                   ; TQ?
  144. X        bne     .signalinit                    ; Yes -- init
  145. X
  146. X        move.w  ie_Qualifier(a1),d0
  147. X        and.w   #LCOM,d0                       ; LCOM?
  148. X        beq     .EventHandled                  ; No
  149. X
  150. X        move.w  _cwkey,d0                      ; Control window key
  151. X        cmp.w   ie_Code(a1),d0
  152. X        beq     .signalcw
  153. X
  154. X        move.w  _insertkey,d0
  155. X        beq     .EventHandled                  ; Key = 0 -- disabled
  156. X
  157. X        cmp.w   ie_Code(a1),d0                 ; The insert key?
  158. X        bne     .EventHandled                  ; No, pass it on
  159. X        bra     .signalinsert                  ; Tell'em to insert
  160. X
  161. X.wait_RAWMOUSE
  162. X        cmp.b   #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
  163. X        bne     .EventHandled                  ; Nope, pass it on
  164. X
  165. X        move.w  ie_Qualifier(a1),d0
  166. X        and.w   _textqual,d0                   ; TQ?
  167. X        bne     .signalinit                    ; Yes
  168. X
  169. X        cmp.w   #LMB,ie_Code(a1)               ; OK, is it SELECTDOWN?
  170. X        bne     .EventHandled                  ; Too bad
  171. X
  172. X        move.w  ie_Qualifier(a1),d0
  173. X        and.w   _gfxqual,d0                    ; GQ?
  174. X        beq     .EventHandled                  ; No, not interested
  175. X
  176. X; Handle event LMB+GQ
  177. X        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
  178. X        move.w  #snapgfx,_action               ; action snapgfx;
  179. X        move.w  #selgfx,_state                 ; state selgfx
  180. X        move.l  _initsignal,d0                 ; Signal init and
  181. X        or.l    _startsignal,d0                ; start
  182. X        bra     SignalTask
  183. X
  184. X.signalinit
  185. X        move.w  #pendsnap,_state
  186. X        move.w  #snapinit,_action
  187. X        move.l  _initsignal,d0                 ; Signal start
  188. X        bsr     Signal
  189. X        bra     .PendSnap
  190. X
  191. X
  192. X; *******************************************************
  193. X; State: PendSnap   TQ
  194. X; Actions     New state           Signal
  195. X; ~TQ         Waiting             cancel
  196. X; LCOM+IKEY   Inserting           insert
  197. X; LMB         SelRegion           start
  198. X; RMB         Inserting           insert
  199. X
  200. X.PendSnap
  201. X        cmp.b   #IECLASS_RAWKEY,ie_Class(a1)   ; RAWKEY?
  202. X        bne     .ps_RAWMOUSE
  203. X        move.w  ie_Qualifier(a1),d0
  204. X        and.w   _textqual,d0                   ; TQ?
  205. X        bne     .ps_IKEY                       ; Still down, continue
  206. X
  207. X;Handle event ~TQ
  208. X.ps_TQ
  209. X        move.w  #noaction,_action              ; no action
  210. X        move.w  #waiting,_state                ; state waiting
  211. X        move.l  _cancelsignal,d0               ; snap cancelled
  212. X        bra     SignalTask
  213. X
  214. X.ps_IKEY
  215. X        move.w  ie_Qualifier(a1),d0
  216. X        and.w   #LCOM,d0                       ; LCOM?
  217. X        beq     .EventHandled                  ; No
  218. X
  219. X        move.w  _cwkey,d0                      ; Control window key
  220. X        cmp.w   ie_Code(a1),d0
  221. X        beq     .signalcw
  222. X
  223. X        move.w  _insertkey,d0
  224. X        beq     .EventHandled                  ; Key = 0 -- disabled
  225. X
  226. X        cmp.w   ie_Code(a1),d0                 ; The insert key?
  227. X        bne     .EventHandled                  ; No, pass it on
  228. X        bra     .signalinsert                  ; Tell'em to insert
  229. X
  230. X.ps_RAWMOUSE
  231. X        cmp.b   #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
  232. X        bne     .EventHandled                  ; Nope, pass it on
  233. X
  234. X        move.w  ie_Qualifier(a1),d0            ; Might be TQ going up.
  235. X        and.w   _textqual,d0                   ; TQ?
  236. X        beq     .ps_TQ
  237. X
  238. X        cmp.w   #LMB,ie_Code(a1)               ; OK, is it SELECTDOWN?
  239. X        bne     .ps_RMB                        ; Too bad
  240. X
  241. X; Handle event LMB+TQ
  242. X        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
  243. X        move.w  #snaptext,_action              ; action snaptext
  244. X        move.w  #selregion,_state              ; state selregion
  245. X        move.l  _startsignal,d0                ; start
  246. X        bra     SignalTask
  247. X
  248. X.ps_RMB
  249. X        cmp.w   #RMB,ie_Code(a1)               ; MENUDOWN
  250. X        bne     .EventHandled
  251. X
  252. X; Handle event RMB+TQ
  253. X.signalinsert
  254. X        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
  255. X
  256. X        move.w  #0,_modinsert
  257. X        move.w  ie_Qualifier(a1),d0
  258. X        and.w   #SHIFT,d0                      ; SHIFT?
  259. X        beq     .NonModified                   ; No
  260. X        move.w  #1,_modinsert
  261. X.NonModified
  262. X        move.w  #insert,_action
  263. X        move.w  #inserting,_state
  264. X        move.l  _insertsignal,d0               ; and insert
  265. X        bra     SignalTask
  266. X
  267. X.signalcw
  268. X        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
  269. X        move.w  #noaction,_action
  270. X        move.w  #waiting,_state
  271. X        move.l  _cancelsignal,d0               ; Exit pending snap
  272. X        or.l    _cwsignal,d0                   ; and tell'em to open window
  273. X        bra     SignalTask
  274. X
  275. X
  276. X; *******************************************************
  277. X; State: SelRegion  LMB+TQ
  278. X; Actions     New state           Signal
  279. X; ~TQ         Waiting             cancel
  280. X; ~LMB        WaitExt
  281. X; MOVE        SelRegion           move
  282. X; RMB         SelRegion           click
  283. X; ~RMB        SelRegion                      Needs no action
  284. X; TIMER       SelRegion           timer
  285. X
  286. X.SelRegion
  287. X        cmp.b   #IECLASS_TIMER,ie_Class(a1)    ; Timer event?
  288. X        bne     .sr_RAWKEY
  289. X
  290. X;Handle timer event
  291. X        move.l  _timersignal,d0
  292. X        bra     SignalTask
  293. X
  294. X.sr_RAWKEY
  295. X        cmp.b   #IECLASS_RAWKEY,ie_Class(a1)   ; RAWKEY?
  296. X        bne     .sr_LMB_UP
  297. X        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
  298. X        move.w  ie_Qualifier(a1),d0
  299. X        and.w   _textqual,d0                   ; TQ?
  300. X        bne     .EventHandled                  ; Still down, continue
  301. X
  302. X;Handle event ~TQ
  303. X.sr_TQ
  304. X        move.w  #cancel,_action                ; no action
  305. X        move.w  #killbutt,_state              ; state waiting
  306. X        move.l  _cancelsignal,d0               ; snap cancelled
  307. X        bra     SignalTask
  308. X
  309. X.sr_LMB_UP
  310. X        cmp.b   #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
  311. X        bne     .EventHandled                  ; Nope, pass it on
  312. X
  313. X        move.w  ie_Qualifier(a1),d0            ; Might be TQ going up.
  314. X        and.w   _textqual,d0                   ; TQ?
  315. X        beq     .sr_TQ
  316. X
  317. X        cmp.w   #LMB_UP,ie_Code(a1)            ; SELECTUP
  318. X        bne     .sr_MOVE                       ; no, check for move
  319. X
  320. X; Handle event ~LMB
  321. X        move.w  #waitext,_state                ; state waitext
  322. X        bra     KillEvent
  323. X
  324. X.sr_MOVE
  325. X        cmp.w   #NO_BUTT,ie_Code(a1)           ; MOVE
  326. X        bne     .sr_RMB                        ; No, check for RMB
  327. X        move.w  ie_Qualifier(a1),d0
  328. X        and.w   #IEQUALIFIER_RELATIVEMOUSE,d0  ; RELATIVEMOUSE
  329. X        beq     .sr_RMB
  330. X
  331. X; Handle event MOVE
  332. X        move.l  _movesignal,d0
  333. X        bra     SignalTask
  334. X
  335. X.sr_RMB
  336. X        cmp.w   #RMB,ie_Code(a1)               ; MENUDOWN
  337. X        bne     .EventHandled                  ; No, not interested
  338. X
  339. X; Handle event RMB
  340. X        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
  341. X        move.l  _clicksignal,d0
  342. X        bra     SignalTask
  343. X
  344. X; ***************************************************
  345. X; State WaitExt     TQ
  346. X; Actions     New state           Signal
  347. X; ~TQ         Waiting             done
  348. X; LMB         SelRegion           click
  349. X; MOVE        WaitExt                            No action needed.
  350. X; RMB         Inserting           done & insert
  351. X; TIMER       WaitExt             timer
  352. X
  353. X.WaitExt
  354. X        cmp.b   #IECLASS_TIMER,ie_Class(a1)    ; Timer event?
  355. X        bne     .we_RAWKEY
  356. X
  357. X;Handle timer event
  358. X        move.l  _timersignal,d0
  359. X        bra     SignalTask
  360. X
  361. X.we_RAWKEY
  362. X        cmp.b   #IECLASS_RAWKEY,ie_Class(a1)   ; RAWKEY?
  363. X        bne     .we_LMB
  364. X        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
  365. X        move.w  ie_Qualifier(a1),d0
  366. X        and.w   _textqual,d0                   ; TQ?
  367. X        bne     .EventHandled                  ; Still down, continue
  368. X
  369. X;Handle event ~TQ
  370. X.we_TQ
  371. X        move.w  #noaction,_action              ; no action
  372. X        move.w  #waiting,_state                ; state waiting
  373. X        move.l  _donesignal,d0                 ; snap finished
  374. X        bra     SignalTask
  375. X
  376. X.we_LMB
  377. X        cmp.b   #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
  378. X        bne     .EventHandled                  ; Nope, pass it on
  379. X
  380. X        move.w  ie_Qualifier(a1),d0            ; Might be TQ going up.
  381. X        and.w   _textqual,d0                   ; TQ?
  382. X        beq     .we_TQ                         ; No.
  383. X
  384. X        cmp.w   #LMB,ie_Code(a1)               ; SELECTDOWN
  385. X        bne     .we_RMB                        ; no, check for RMB
  386. X
  387. X; Handle event LMB
  388. X        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
  389. X        move.w  #selregion,_state              ; state waitext
  390. X        move.l  _clicksignal,d0                ; Extend selection
  391. X        bra     SignalTask
  392. X
  393. X.we_RMB
  394. X        cmp.w   #RMB,ie_Code(a1)               ; MENUDOWN
  395. X        bne     .EventHandled                  ; No, not interested
  396. X
  397. X; Handle event RMB
  398. X        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
  399. X        move.w  #insert,_action
  400. X        move.w  #inserting,_state
  401. X        move.l  _donesignal,d0
  402. X        or.l    _insertsignal,d0
  403. X        bra     SignalTask
  404. X
  405. X; *******************************************************
  406. X; State: SelGfx     LMB+GQ
  407. X; Actions     New state           Signal
  408. X; ~GQ         Waiting             cancel
  409. X; ~LMB        WaitGfx
  410. X; MOVE        SelGfx              move
  411. X; TIMER       SelGfx              timer
  412. X; RMB         SelGfx                        removed
  413. X
  414. X.SelGfx
  415. X        cmp.b   #IECLASS_TIMER,ie_Class(a1)    ; Timer event?
  416. X        bne     .sg_RAWKEY
  417. X
  418. X;Handle timer event
  419. X        move.l  _timersignal,d0
  420. X        bra     SignalTask
  421. X
  422. X.sg_RAWKEY
  423. X        cmp.b   #IECLASS_RAWKEY,ie_Class(a1)   ; RAWKEY?
  424. X        bne     .sg_LMB_UP
  425. X        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
  426. X        move.w  ie_Qualifier(a1),d0
  427. X        and.w   _gfxqual,d0                    ; GQ?
  428. X        bne     .EventHandled                  ; Still down, continue
  429. X
  430. X;Handle event ~GQ
  431. X.sg_GQ
  432. X        move.w  #cancel,_action                ; cancelling snap
  433. X        move.w  #killbutt,_state               ; Kill obsolete button
  434. X        move.l  _cancelsignal,d0               ; snap cancelled
  435. X        bra     SignalTask
  436. X
  437. X.sg_LMB_UP
  438. X        cmp.b   #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
  439. X        bne     .EventHandled                  ; Nope, pass it on
  440. X
  441. X        move.w  ie_Qualifier(a1),d0            ; Might be GQ going up.
  442. X        and.w   _gfxqual,d0                    ; GQ?
  443. X        beq     .sg_GQ
  444. X
  445. X        cmp.w   #LMB_UP,ie_Code(a1)            ; SELECTUP
  446. X        bne     .sg_MOVE                       ; no, check for move
  447. X
  448. X; Handle event ~LMB
  449. X        move.w  #waitgfx,_state                ; state waitext
  450. X        bra     KillEvent
  451. X
  452. X.sg_MOVE
  453. X        cmp.w   #NO_BUTT,ie_Code(a1)           ; MOVE
  454. X        bne     .EventHandled                  ; No, check for RMB
  455. X        move.w  ie_Qualifier(a1),d0
  456. X        and.w   #IEQUALIFIER_RELATIVEMOUSE,d0  ; RELATIVEMOUSE
  457. X        beq     .EventHandled
  458. X
  459. X; Handle event MOVE
  460. X        move.l  _movesignal,d0
  461. X        bra     SignalTask
  462. X
  463. X.sg_RMB
  464. X        bra     KillEvent
  465. X
  466. X; ***************************************************
  467. X; State WaitGfx     GQ
  468. X; Actions     New state           Signal
  469. X; ~GQ         Waiting             done
  470. X; LMB         SelGfx              click
  471. X; MOVE        WaitGfx                            No action needed.
  472. X; TIMER       WaitGfx             timer
  473. X; RMB         WaitGfx             --             remove event
  474. X
  475. X.WaitGfx
  476. X        cmp.b   #IECLASS_TIMER,ie_Class(a1)    ; Timer event?
  477. X        bne     .wg_RAWKEY
  478. X
  479. X;Handle timer event
  480. X        move.l  _timersignal,d0
  481. X        bra     SignalTask
  482. X
  483. X.wg_RAWKEY
  484. X        cmp.b   #IECLASS_RAWKEY,ie_Class(a1)   ; RAWKEY?
  485. X        bne     .wg_LMB
  486. X        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
  487. X        move.w  ie_Qualifier(a1),d0
  488. X        and.w   _gfxqual,d0                    ; GQ?
  489. X        bne     .EventHandled                  ; Still down, continue
  490. X
  491. X;Handle event ~GQ
  492. X.wg_GQ
  493. X        move.w  #noaction,_action              ; no action
  494. X        move.w  #waiting,_state                ; state waiting
  495. X        move.l  _donesignal,d0                 ; snap finished
  496. X        bra     SignalTask
  497. X
  498. X.wg_LMB
  499. X        cmp.b   #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
  500. X        bne     .EventHandled                  ; Nope, pass it on
  501. X
  502. X        move.w  ie_Qualifier(a1),d0            ; Might be GQ going up
  503. X        and.w   _gfxqual,d0                    ; GQ?
  504. X        beq     .wg_GQ
  505. X
  506. X        cmp.w   #LMB,ie_Code(a1)               ; SELECTDOWN
  507. X        bne     .wg_RMB                          ; no -- finished
  508. X
  509. X; Handle event LMB
  510. X        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
  511. X        move.w  #selgfx,_state                 ; state waitext
  512. X        move.l  _clicksignal,d0                ; Extend selection
  513. X        bra     SignalTask
  514. X
  515. X.wg_RMB
  516. X        cmp.w   #NO_BUTT,ie_Code(a1)           ; Any button?
  517. X        beq     .EventHandled                  ; No, moves are ok
  518. X
  519. X        bra     KillEvent
  520. X
  521. X
  522. X; ***************************************************
  523. X; State CancelTxt
  524. X; Make sure that the Button Up event that we've got
  525. X; hanging around doesn't get through.
  526. X
  527. X.CancelTxt
  528. X        cmp.b   #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
  529. X        bne     .EventHandled                  ; Nope, just pass it on
  530. X
  531. X        cmp.w   #LMB_UP,ie_Code(a1)            ; The button?
  532. X        bne     .EventHandled                  ; No
  533. X
  534. X        move.w  #noaction,_action
  535. X        move.w  #waiting,_state
  536. X        bra     KillEvent
  537. X
  538. X; ***************************************************
  539. X; State Insert
  540. X; Snap actions are removed, the rest are passed along.
  541. X
  542. X.Insert
  543. X        cmp.b   #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
  544. X        bne     .EventHandled                  ; Nope, pass it on
  545. X
  546. X        cmp.w   #LMB,ie_Code(a1)               ; Left mouse button
  547. X        bne     .insert_TQ                     ; No -- just kill
  548. X
  549. X        move.w  #noaction,_action              ; Cancel paste
  550. X
  551. X.insert_TQ
  552. X        move.w  ie_Qualifier(a1),d0
  553. X        and.w   _textqual,d0                   ; TQ?
  554. X        beq     .EventHandled                  ; no
  555. X
  556. X        cmp.w   #NO_BUTT,ie_Code(a1)           ; Any button?
  557. X        beq     .EventHandled                  ; No, moves are ok
  558. X
  559. XKillEvent:
  560. X        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
  561. X        bra     .EventHandled
  562. X
  563. XSignalTask:
  564. X        bsr     Signal
  565. X
  566. X.EventHandled
  567. X        move.l  ie_NextEvent(a1),a1             ; Get next event
  568. X        bra     .nextevent
  569. X
  570. X.done
  571. X        movem.l (sp)+,a4
  572. X        move.l  a0,d0
  573. X        rts
  574. X
  575. XSignal:
  576. X        movem.l a0-a2/a6,-(sp)
  577. X        move.l  _MyTask,a1
  578. X        move.l  _SysBase,a6                     ;  Get ExecBase for Signal
  579. X        jsr     _LVOSignal(a6)
  580. X        movem.l (sp)+,a0-a2/a6
  581. X        rts
  582. X
  583. X        end
  584. END_OF_FILE
  585. if test 17796 -ne `wc -c <'source/handler.s'`; then
  586.     echo shar: \"'source/handler.s'\" unpacked with wrong size!
  587. fi
  588. # end of 'source/handler.s'
  589. fi
  590. if test -f 'source/minrexx.c' -a "${1}" != "-c" ; then 
  591.   echo shar: Will not clobber existing file \"'source/minrexx.c'\"
  592. else
  593. echo shar: Extracting \"'source/minrexx.c'\" \(15411 characters\)
  594. sed "s/^X//" >'source/minrexx.c' <<'END_OF_FILE'
  595. X#ifdef SNAPREXX
  596. X/*
  597. X *   This is an example of how REXX messages might be handled.  This is
  598. X *   a `minimum' example that both accepts asynchronous REXX messages and
  599. X *   can request REXX service.
  600. X *
  601. X *   Read this entire file!  It's short enough.
  602. X *
  603. X *   It is written in such a fashion that it can be attached to a program
  604. X *   with a minimum of fuss.  The only external symbols it makes available
  605. X *   are the seven functions and RexxSysBase.
  606. X *
  607. X *   This code is by Radical Eye Software, but it is put in the public
  608. X *   domain.  I would appreciate it if the following string was left in
  609. X *   both as a version check and as thanks from you for the use of this
  610. X *   code.
  611. X *
  612. X *   If you modify this file for your own use, don't bump the version
  613. X *   number; add a suffix, such as 1.0a or 1.0.3 or something, so we
  614. X *   don't have fake `versions' floating around.
  615. X */
  616. Xstatic char *blurb = "Radical Eye MinRexx 0.4" ;
  617. X/*
  618. X *   We read in our own personal little include.
  619. X */
  620. X#include "minrexx.h"
  621. X/*
  622. X *   All of our local globals, hidden from sight.
  623. X */
  624. Xstatic struct MsgPort *rexxPort ;          /* this is *our* rexx port */
  625. Xstatic int bringerdown ;                   /* are we trying to shut down? */
  626. Xstatic struct rexxCommandList *globalrcl ; /* our command association list */
  627. Xstatic long stillNeedReplies ;             /* how many replies are pending? */
  628. Xstatic long rexxPortBit ;                  /* what bit to wait on for Rexx? */
  629. Xstatic char *extension ;                   /* the extension for macros */
  630. Xstatic int (*userdisp)() ;                 /* the user's dispatch function */
  631. Xstatic struct RexxMsg *oRexxMsg ;          /* the outstanding Rexx message */
  632. X/*
  633. X *   Our library base.  Don't you dare close this!
  634. X */
  635. Xstruct RxsLib *RexxSysBase ;
  636. X/*
  637. X *   This is the main entry point into this code.
  638. X */
  639. Xlong upRexxPort(s, rcl, exten, uf)
  640. X/*
  641. X *   The first argument is the name of your port to be registered;
  642. X *   this will be used, for instance, with the `address' command of ARexx.
  643. X */
  644. Xchar *s ;
  645. X/*
  646. X *   The second argument is an association list of command-name/user-data
  647. X *   pairs.  It's an array of struct rexxCommandList, terminated by a
  648. X *   structure with a NULL in the name field. The commands are case
  649. X *   sensitive.  The user-data field can contain anything appropriate,
  650. X *   perhaps a function to call or some other data.
  651. X */
  652. Xstruct rexxCommandList *rcl ;
  653. X/*
  654. X *   The third argument is the file extension for ARexx macros invoked
  655. X *   by this program.  If you supply this argument, any `primitive' not
  656. X *   in the association list rcl will be sent out to ARexx for
  657. X *   interpretation, thus allowing macro programs to work just like
  658. X *   primitives.  If you do not want this behavior, supply a `NULL'
  659. X *   here, and those commands not understood will be replied with an
  660. X *   error value of RXERRORNOCMD.
  661. X */
  662. Xchar *exten ;
  663. X/*
  664. X *   The fourth argument is the user dispatch function.  This function
  665. X *   will *only* be called from rexxDisp(), either from the user calling
  666. X *   this function directly, or from dnRexxPort().  Anytime a command
  667. X *   match is found in the association list, this user-supplied function
  668. X *   will be called with two arguments---the Rexx message that was
  669. X *   received, and a pointer to the association pair.  This function
  670. X *   should return a `1' if the message was replied to by the function
  671. X *   and a `0' if the default success code of (0, 0) should be returned.
  672. X *   Note that the user function should never ReplyMsg() the message;
  673. X *   instead he should indicate the return values with replyRexxCmd();
  674. X *   otherwise we lose track of the messages that still lack replies.
  675. X */
  676. Xint (*uf)() ;
  677. X/*
  678. X *   upRexxPort() returns the signal bit to wait on for Rexx messages.
  679. X *   If something goes wrong, it simply returns a `0'.  Note that this
  680. X *   function is safe to call multiple times because we check to make
  681. X *   sure we haven't opened already.  It's also a quick way to change
  682. X *   the association list or dispatch function.
  683. X */
  684. X{
  685. X   struct MsgPort *FindPort() ;
  686. X   struct MsgPort *CreatePort() ;
  687. X
  688. X/*
  689. X *   Some basic error checking.
  690. X */
  691. X   if (rcl == NULL || uf == NULL)
  692. X      return(0L) ;
  693. X/*
  694. X *   If we aren't open, we make sure no one else has opened a port with
  695. X *   this name already.  If that works, and the createport succeeds, we
  696. X *   fill rexxPortBit with the value to return.
  697. X *
  698. X *   Note that rexxPortBit will be 0 iff rexxPort is NULL, so the check
  699. X *   for rexxPort == NULL also insures that our rexxPortBit is 0.
  700. X */
  701. X   if (rexxPort == NULL) {
  702. X      Forbid() ;
  703. X      if (FindPort(s)==NULL)
  704. X         rexxPort = CreatePort(s, 0L) ;
  705. X      Permit() ;
  706. X      if (rexxPort != NULL)
  707. X         rexxPortBit = 1L << rexxPort->mp_SigBit ;
  708. X   }
  709. X/*
  710. X *   Squirrel away these values for our own internal access, and return
  711. X *   the wait bit.
  712. X */
  713. X   globalrcl = rcl ;
  714. X   extension = exten ;
  715. X   userdisp = uf ;
  716. X   return(rexxPortBit) ;
  717. X}
  718. X/*
  719. X *   This function closes the rexx library, but only if it is open
  720. X *   and we aren't expecting further replies from REXX.  It's
  721. X *   *private*, but it doesn't have to be; it's pretty safe to
  722. X *   call anytime.
  723. X */
  724. Xstatic void closeRexxLib() {
  725. X   if (stillNeedReplies == 0 && RexxSysBase) {
  726. X      CloseLibrary(RexxSysBase) ;
  727. X      RexxSysBase = NULL ;
  728. X   }
  729. X}
  730. X/*
  731. X *   This function closes down the Rexx port.  It is always safe to
  732. X *   call, and should *definitely* be made a part of your cleanup
  733. X *   routine.  No arguments and no return.  It removes the Rexx port,
  734. X *   replies to all of the messages and insures that we get replies
  735. X *   to all the ones we sent out, closes the Rexx library, deletes the
  736. X *   port, clears a few flags, and leaves.
  737. X */
  738. Xvoid dnRexxPort() {
  739. X   if (rexxPort) {
  740. X      RemPort(rexxPort) ;
  741. X      bringerdown = 1 ;
  742. X/*
  743. X *   A message still hanging around?  We kill it off.
  744. X */
  745. X      if (oRexxMsg) {
  746. X         oRexxMsg->rm_Result1 = RXERRORIMGONE ;
  747. X         ReplyMsg(oRexxMsg) ;
  748. X         oRexxMsg = NULL ;
  749. X      }
  750. X      while (stillNeedReplies) {
  751. X         WaitPort(rexxPort) ;
  752. X         dispRexxPort() ;
  753. X      }
  754. X      closeRexxLib() ;
  755. X      DeletePort(rexxPort) ;
  756. X      rexxPort = NULL ;
  757. X   }
  758. X   rexxPortBit = 0 ;
  759. X}
  760. X/*
  761. X *   Here we dispatch any REXX messages that might be outstanding.
  762. X *   This is the main routine for handling Rexx messages.
  763. X *   This function is fast if no messages are outstanding, so it's
  764. X *   pretty safe to call fairly often.
  765. X *
  766. X *   If we are bring the system down and flushing messages, we reply
  767. X *   with a pretty serious return code RXERRORIMGONE.
  768. X *
  769. X *   No arguments, no returns.
  770. X */
  771. Xvoid dispRexxPort() {
  772. X   register struct RexxMsg *RexxMsg ;
  773. X   int cmdcmp() ;
  774. X   register struct rexxCommandList *rcl ;
  775. X   register char *p ;
  776. X   register int dontreply ;
  777. X
  778. X/*
  779. X *   If there's no rexx port, we're out of here.
  780. X */
  781. X   if (rexxPort == NULL)
  782. X      return ;
  783. X/*
  784. X *   Otherwise we have our normal loop on messages.
  785. X */
  786. X   while (RexxMsg = (struct RexxMsg *)GetMsg(rexxPort)) {
  787. X/*
  788. X *   If we have a reply to a message we sent, we look at the second
  789. X *   argument.  If it's set, it's a function we are supposed to call
  790. X *   so we call it.  Then, we kill the argstring and the message
  791. X *   itself, decrement the outstanding count, and attempt to close
  792. X *   down the Rexx library.  Note that this call only succeeds if
  793. X *   there are no outstanding messages.  Also, it's pretty quick, so
  794. X *   don't talk to me about efficiency.
  795. X */
  796. X      if (RexxMsg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG) {
  797. X         if (RexxMsg->rm_Args[1]) {
  798. X            ((int (*)())(RexxMsg->rm_Args[1]))(RexxMsg) ;
  799. X         }
  800. X         DeleteArgstring(RexxMsg->rm_Args[0]) ;
  801. X         DeleteRexxMsg(RexxMsg) ;
  802. X         stillNeedReplies-- ;
  803. X         closeRexxLib() ;
  804. X/*
  805. X *   The default case is we got a message and we need to check it for
  806. X *   primitives.  We skip past any initial tabs or spaces and initialize
  807. X *   the return code fields.
  808. X */
  809. X      } else {
  810. X         p = (char *)RexxMsg->rm_Args[0] ;
  811. X         while (*p > 0 && *p <= ' ')
  812. X            p++ ;
  813. X         RexxMsg->rm_Result1 = 0 ;
  814. X         RexxMsg->rm_Result2 = 0 ;
  815. X/*
  816. X *   If somehow the reply is already done or postponed, `dontreply' is
  817. X *   set.
  818. X */
  819. X         dontreply = 0 ;
  820. X/*
  821. X *   If the sky is falling, we just blow up and replymsg.
  822. X */
  823. X         if (bringerdown) {
  824. X            RexxMsg->rm_Result1 = RXERRORIMGONE ;
  825. X/*
  826. X *   Otherwise we cdr down our association list, comparing commands,
  827. X *   until we get a match.  If we get a match, we call the dispatch
  828. X *   function with the appropriate arguments, and break out.
  829. X */
  830. X         } else {
  831. X            oRexxMsg = RexxMsg ;
  832. X            for (rcl = globalrcl; rcl->name; rcl++) {
  833. X               if (cmdcmp(rcl->name, p) == 0) {
  834. X                  userdisp(RexxMsg, rcl, p+strlen(rcl->name)) ;
  835. X                  break ;
  836. X               }
  837. X            }
  838. X/*
  839. X *   If we broke out, rcl will point to the command we executed; if we
  840. X *   are at the end of the list, we didn't understand the command.  In
  841. X *   this case, if we were supplied an extension in upRexxPort, we know
  842. X *   that we should send the command out, so we do so, synchronously.
  843. X *   The synchronous send takes care of our reply.  If we were given a
  844. X *   NULL extension, we bitch that the command didn't make sense to us.
  845. X */
  846. X            if (rcl->name == NULL) {
  847. X               if (extension) {
  848. X                  syncRexxCmd(RexxMsg->rm_Args[0], RexxMsg) ;
  849. X                  dontreply = 1 ;
  850. X               } else {
  851. X                  RexxMsg->rm_Result1 = RXERRORNOCMD ;
  852. X               }
  853. X            }
  854. X         }
  855. X/*
  856. X *   Finally, reply if appropriate.
  857. X */
  858. X         oRexxMsg = NULL ;
  859. X         if (! dontreply)
  860. X            ReplyMsg(RexxMsg) ;
  861. X      }
  862. X   }
  863. X}
  864. X/*
  865. X *   This is the function we use to see if the command matches
  866. X *   the command string.  Not case sensitive, and the real command only
  867. X *   need be a prefix of the command string.  Make sure all commands
  868. X *   are given in lower case!
  869. X */
  870. Xstatic int cmdcmp(c, m)
  871. Xregister char *c, *m ;
  872. X{
  873. X   while (*c && ((*c == *m) || (*c == *m + 32 && ('a' <= *c && *c <= 'z')))) {
  874. X      c++ ;
  875. X      m++ ;
  876. X   }
  877. X   return(*c) ;
  878. X}
  879. X/*
  880. X *   Opens the Rexx library if unopened.  Returns success (1) or
  881. X *   failure (0).  This is another function that is *private* but
  882. X *   that doesn't have to be.
  883. X */
  884. Xstatic int openRexxLib() {
  885. X   if (RexxSysBase)
  886. X      return(1) ;
  887. X   return((RexxSysBase = (struct RxsLib *)OpenLibrary(RXSNAME, 0L)) != NULL) ;
  888. X}
  889. X/*
  890. X *   This is the general ARexx command interface, but is not the one
  891. X *   you will use most of the time; ones defined later are easier to
  892. X *   understand and use.  But they all go through here.
  893. X */
  894. Xstruct RexxMsg *sendRexxCmd(s, f, p1, p2, p3)
  895. Xchar *s ;
  896. X/*
  897. X *   The first parameter is the command to send to Rexx.
  898. X */
  899. Xint (*f)() ;
  900. X/*
  901. X *   The second parameter is either NULL, indicating that the command
  902. X *   should execute asynchronously, or a function to be called when the
  903. X *   message we build up and send out here finally returns.  Please note
  904. X *   that the function supplied here could be called during cleanup after
  905. X *   a fatal error, so make sure it is `safe'.  This function always is
  906. X *   passed one argument, the RexxMsg that is being replied.
  907. X */
  908. XSTRPTR p1, p2, p3 ;
  909. X/*
  910. X *   These are up to three arguments to be stuffed into the RexxMsg we
  911. X *   are building up, making the values available when the message is
  912. X *   finally replied to.  The values are stuffed into Args[2]..Args[4].
  913. X */
  914. X{
  915. X   struct RexxMsg *CreateRexxMsg() ;
  916. X   STRPTR CreateArgstring() ;
  917. X   register struct MsgPort *rexxport ;
  918. X   register struct RexxMsg *RexxMsg ;
  919. X
  920. X/*
  921. X *   If we have too many replies out there, we just return failure.
  922. X *   Note that you should check the return code to make sure your
  923. X *   message got out!  Then, we forbid, and make sure that:
  924. X *      - we have a rexx port open
  925. X *      - Rexx is out there
  926. X *      - the library is open
  927. X *      - we can create a message
  928. X *      - we can create an argstring
  929. X *
  930. X *   If all of these succeed, we stuff a few values and send the
  931. X *   message, permit, and return.
  932. X */
  933. X   if (rexxPort == NULL || stillNeedReplies > MAXRXOUTSTANDING-1)
  934. X      return(NULL) ;
  935. X   RexxMsg = NULL ;
  936. X   if (openRexxLib() && (RexxMsg =
  937. X             CreateRexxMsg(rexxPort, extension, rexxPort->mp_Node.ln_Name)) &&
  938. X             (RexxMsg->rm_Args[0] = CreateArgstring(s, (long)strlen(s)))) {
  939. X      RexxMsg->rm_Action = RXCOMM ;
  940. X      RexxMsg->rm_Args[1] = (STRPTR)f ;
  941. X      RexxMsg->rm_Args[2] = p1 ;
  942. X      RexxMsg->rm_Args[3] = p2 ;
  943. X      RexxMsg->rm_Args[4] = p3 ;
  944. X      RexxMsg->rm_Node.mn_Node.ln_Name = RXSDIR ;
  945. X      Forbid() ;
  946. X      if (rexxport = FindPort(RXSDIR))
  947. X         PutMsg(rexxport, RexxMsg) ;
  948. X      Permit() ;
  949. X      if (rexxport) {
  950. X         stillNeedReplies++ ;
  951. X         return(RexxMsg) ;
  952. X      } else
  953. X         DeleteArgstring(RexxMsg->rm_Args[0]) ;
  954. X   }
  955. X   if (RexxMsg)
  956. X      DeleteRexxMsg(RexxMsg) ;
  957. X   closeRexxLib() ;
  958. X   return(NULL) ;
  959. X}
  960. X/*
  961. X *   This function is used to send out an ARexx message and return
  962. X *   immediately.  Its single parameter is the command to send.
  963. X */
  964. Xstruct RexxMsg *asyncRexxCmd(s)
  965. Xchar *s ;
  966. X{
  967. X   return(sendRexxCmd(s, NULL, NULL, NULL, NULL)) ;
  968. X}
  969. X/*
  970. X *   This function sets things up to reply to the message that caused
  971. X *   it when we get a reply to the message we are sending out here.
  972. X *   But first the function we pass in, which actually handles the reply.
  973. X *   Note how we get the message from the Args[2]; Args[0] is the command,
  974. X *   Args[1] is this function, and Args[2]..Args[4] are any parameters
  975. X *   passed to sendRexxCmd() as p1..p3.  We pass the result codes right
  976. X *   along.
  977. X */
  978. Xstatic void replytoit(msg)
  979. Xregister struct RexxMsg *msg ;
  980. X{
  981. X   register struct RexxMsg *omsg ;
  982. X
  983. X   omsg = (struct RexxMsg *)(msg->rm_Args[2]) ;
  984. X   replyRexxCmd(omsg, msg->rm_Result1, msg->rm_Result2, NULL) ;
  985. X   ReplyMsg(omsg) ;
  986. X}
  987. X/*
  988. X *   This function makes use of everything we've put together so far,
  989. X *   and functions as a synchronous Rexx call; as soon as the macro
  990. X *   invoked here returns, we reply to `msg', passing the return codes
  991. X *   back.
  992. X */
  993. Xstruct RexxMsg *syncRexxCmd(s, msg)
  994. Xchar *s ;
  995. Xstruct RexxMsg *msg ;
  996. X{
  997. X   return(sendRexxCmd(s, (APTR)&replytoit, msg, NULL, NULL)) ;
  998. X}
  999. X/*
  1000. X *   There are times when you want to pass back return codes or a
  1001. X *   return string; call this function when you want to do that,
  1002. X *   and return `1' from the user dispatch function so the main
  1003. X *   event loop doesn't reply (because we reply here.)  This function
  1004. X *   always returns 1.
  1005. X */
  1006. Xvoid replyRexxCmd(msg, primary, secondary, string)
  1007. X/*
  1008. X *   The first parameter is the message we are replying to.
  1009. X */
  1010. Xregister struct RexxMsg *msg ;
  1011. X/*
  1012. X *   The next two parameters are the primary and secondary return
  1013. X *   codes.
  1014. X */
  1015. Xregister long primary, secondary ;
  1016. X/*
  1017. X *   The final parameter is a return string.  This string is only
  1018. X *   returned if the primary return code is 0, and a string was
  1019. X *   requested.
  1020. X *
  1021. X *   We also note that we have replied to the message that came in.
  1022. X */
  1023. Xregister char *string ;
  1024. X{
  1025. X   STRPTR CreateArgstring() ;
  1026. X
  1027. X/*
  1028. X *   Note how we make sure the Rexx Library is open before calling
  1029. X *   CreateArgstring . . . and we close it down at the end, if possible.
  1030. X */
  1031. X   if (primary == 0 && (msg->rm_Action & (1L << RXFB_RESULT))) {
  1032. X      if (string && openRexxLib())
  1033. X         secondary = (long)CreateArgstring(string, (long)strlen(string)) ;
  1034. X      else
  1035. X         secondary = 0L ;
  1036. X   }
  1037. X   msg->rm_Result1 = primary ;
  1038. X   msg->rm_Result2 = secondary ;
  1039. X   closeRexxLib() ;
  1040. X}
  1041. X#endif
  1042. END_OF_FILE
  1043. if test 15411 -ne `wc -c <'source/minrexx.c'`; then
  1044.     echo shar: \"'source/minrexx.c'\" unpacked with wrong size!
  1045. fi
  1046. # end of 'source/minrexx.c'
  1047. fi
  1048. if test -f 'source/snapchars.c' -a "${1}" != "-c" ; then 
  1049.   echo shar: Will not clobber existing file \"'source/snapchars.c'\"
  1050. else
  1051. echo shar: Extracting \"'source/snapchars.c'\" \(21526 characters\)
  1052. sed "s/^X//" >'source/snapchars.c' <<'END_OF_FILE'
  1053. X/* Auto: make
  1054. X*/
  1055. X
  1056. XIMPORT struct SnapRsrc *SnapRsrc;
  1057. X
  1058. X#define COPY 0xC0L
  1059. X#define INVCOPY 0x30L
  1060. X#define CopyChar(_x, _y, _m)                                  \
  1061. X    BltBitMap(&MyBM, (LONG)_x, (LONG)_y,                      \
  1062. X      &TempBM, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight,     \
  1063. X      _m, -1L, NULL);                                         \
  1064. X    WaitBlit()
  1065. X
  1066. XWORD Unit;
  1067. XWORD Pattern[5] = {
  1068. X    0,
  1069. X    0x0c3f,     /* Frame ....oo....oooooo */
  1070. X    0x3333,     /* Char  ..oo..oo..oo..oo */
  1071. X    0x1f1f,     /* Word  ...ooooo...ooooo */
  1072. X    0xffff      /* Line  oooooooooooooooo */
  1073. X};
  1074. X
  1075. XIMPORT LONG xl; /* leftmost x position */
  1076. XIMPORT LONG xr; /* rightmost x position */
  1077. XIMPORT LONG yt; /* topmost y position */
  1078. XIMPORT LONG yb; /* bottommost y position */
  1079. XLONG minx; /* left limit */
  1080. XLONG maxx; /* right limit */
  1081. XLONG maxy; /* bottom limit */
  1082. XLONG tl, tr; /* used by findword - left and right edge of word */
  1083. XWORD fw, fh; /* Font width and height used when drawing the frame */
  1084. XWORD GZZ;
  1085. XWORD SBM;
  1086. X
  1087. XIMPORT LONG mx, my; /* Mouse position in character steps */
  1088. X#define closetop     0
  1089. X#define closebottom  1
  1090. XWORD closey;
  1091. X#define closeleft   0
  1092. X#define closeright  1
  1093. XWORD closex;
  1094. X
  1095. X
  1096. Xstruct Window *window;  /* The window we're snapping from */
  1097. X
  1098. X/* Data for font being snapped */
  1099. XUWORD FontHeight;
  1100. XUWORD FontWidth;
  1101. XUWORD Underscore;
  1102. XUBYTE FontType;
  1103. XUBYTE LoChar;
  1104. XUBYTE HiChar;
  1105. XUWORD Modulo;
  1106. XUWORD *CharLoc;
  1107. XUWORD NoOfChars;
  1108. XUBYTE *SrcData;
  1109. XIMPORT UBYTE *CharData;
  1110. XUBYTE IFlags;
  1111. X
  1112. XIMPORT struct RastPort TempRp, MyRP;
  1113. XIMPORT struct BitMap TempBM, MyBM;
  1114. X
  1115. XIMPORT UWORD *TempRaster;   /* Used for character recognition */
  1116. X
  1117. XIMPORT struct Screen *theScreen;
  1118. XIMPORT struct RastPort rp;
  1119. Xstruct Layer *LockedLayer;
  1120. X
  1121. XIMPORT LONGBITS cancelsignal, donesignal, movesignal, clicksignal, timersignal;
  1122. XIMPORT WORD action;
  1123. X
  1124. XWORD starting;
  1125. X
  1126. X/* Init vars with font data.
  1127. X*/
  1128. X
  1129. XVOID SetSnapFont(font)
  1130. Xstruct TextFont *font;
  1131. X{
  1132. X    if (!font) {
  1133. X        FontWidth = -1;
  1134. X        return;
  1135. X    }
  1136. X    FontHeight = font->tf_YSize;
  1137. X    Underscore = font->tf_Baseline + 1;
  1138. X    FontType = font->tf_Flags;
  1139. X    FontWidth = (FontType & FPF_PROPORTIONAL ? -1 : font->tf_XSize);
  1140. X    if (FontWidth == -1) {
  1141. X        return;
  1142. X    }
  1143. X    LoChar = font->tf_LoChar;
  1144. X    HiChar = font->tf_HiChar;
  1145. X    Modulo = font->tf_Modulo;
  1146. X    CharLoc = (UWORD *)font->tf_CharLoc;
  1147. X    NoOfChars = HiChar - LoChar + 1;
  1148. X    Modulo = font->tf_Modulo;
  1149. X    SrcData = (UBYTE *)font->tf_CharData;
  1150. X    BltClear(CharData, 256L * 32, 0L);
  1151. X    WaitBlit();
  1152. X    CopyFont();
  1153. X}
  1154. X
  1155. X/* Check if the character at x, y is a space
  1156. X*/
  1157. X
  1158. XWORD IsSpace(x, y)
  1159. XLONG x, y;
  1160. X{
  1161. X    REGISTER WORD i = FontHeight - 1;
  1162. X    REGISTER UWORD *data = &TempRaster[i];
  1163. X
  1164. X      /* Copy character at x, y */
  1165. X    BltClear((char *)TempRaster, 32L, 0L);
  1166. X    ClipBlit(&rp, x, y,
  1167. X      &TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, COPY);
  1168. X    WaitBlit();
  1169. X
  1170. X    if (*data) {         /* Try inverted copy */
  1171. X        ClipBlit(&rp, x, y,
  1172. X          &TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, INVCOPY);
  1173. X        WaitBlit();
  1174. X    }
  1175. X    while (i--) {
  1176. X        if (*data--) {
  1177. X            return 0;
  1178. X        }
  1179. X    }
  1180. X    return 1;
  1181. X}
  1182. X
  1183. X#define ShortFrame 4L      /* Square frame - columnar select */
  1184. X#define LongFrame  8L      /* Strange frame - char or word select */
  1185. XIMPORT LONG OFType;        /* Old frame type: ShortFrame/LongFrame */
  1186. XIMPORT UWORD Ptrn;
  1187. XIMPORT Point OldFrame[];
  1188. XIMPORT Point NewFrame[];
  1189. X
  1190. X
  1191. X/* update_frame calculates the new frame,
  1192. X** erases the old frame and draws the new one.
  1193. X** It's all pretty obvious if you take it slowly.
  1194. X*/
  1195. XVOID update_frame()
  1196. X{
  1197. X    LONG ft;
  1198. X    switch (Unit) {
  1199. X        case UNIT_FRAME: {
  1200. X              /*********\
  1201. X              *         *
  1202. X              *         *
  1203. X              \*********/
  1204. X            NewFrame[0].x = xl - 1;  NewFrame[0].y = yt - 1;
  1205. X            NewFrame[1].x = xr + fw; NewFrame[1].y = yt - 1;
  1206. X            NewFrame[2].x = xr + fw; NewFrame[2].y = yb + fh;
  1207. X            NewFrame[3].x = xl - 1;  NewFrame[3].y = yb + fh;
  1208. X            NewFrame[4].x = xl - 1;  NewFrame[4].y = yt - 1;
  1209. X            ft = ShortFrame;
  1210. X            break;
  1211. X        }
  1212. X        case UNIT_CHAR:
  1213. X        case UNIT_WORD: {
  1214. X            if (yt == yb) {   /* On the same line - same as UNIT_FRAME */
  1215. X                NewFrame[0].x = xl - 1;  NewFrame[0].y = yt - 1;
  1216. X                NewFrame[1].x = xr + fw; NewFrame[1].y = yt - 1;
  1217. X                NewFrame[2].x = xr + fw; NewFrame[2].y = yb + fh;
  1218. X                NewFrame[3].x = xl - 1;  NewFrame[3].y = yb + fh;
  1219. X                NewFrame[4].x = xl - 1;  NewFrame[4].y = yt - 1;
  1220. X                ft = ShortFrame;
  1221. X            } else {
  1222. X                      /*****\
  1223. X                 ******     *
  1224. X                 *          *
  1225. X                 *      *****
  1226. X                 *******/
  1227. X                NewFrame[0].x = xl - 1;    NewFrame[0].y = yt - 1;
  1228. X                NewFrame[1].x = maxx + fw; NewFrame[1].y = yt - 1;
  1229. X                NewFrame[2].x = maxx + fw; NewFrame[2].y = yb;
  1230. X                NewFrame[3].x = xr + fw;   NewFrame[3].y = yb;
  1231. X                NewFrame[4].x = xr + fw;   NewFrame[4].y = yb + fh;
  1232. X                NewFrame[5].x = minx - 1;  NewFrame[5].y = yb + fh;
  1233. X                NewFrame[6].x = minx - 1;  NewFrame[6].y = yt + fh;
  1234. X                NewFrame[7].x = xl - 1;    NewFrame[7].y = yt + fh;
  1235. X                NewFrame[8].x = xl - 1;    NewFrame[8].y = yt - 1;
  1236. X                ft = LongFrame;
  1237. X            }
  1238. X            break;
  1239. X        }
  1240. X        case UNIT_LINE: {
  1241. X            NewFrame[0].x = minx - 1;  NewFrame[0].y = yt - 1;
  1242. X            NewFrame[1].x = maxx + fw; NewFrame[1].y = yt - 1;
  1243. X            NewFrame[2].x = maxx + fw; NewFrame[2].y = yb + fh;
  1244. X            NewFrame[3].x = minx - 1;  NewFrame[3].y = yb + fh;
  1245. X            NewFrame[4].x = minx - 1;  NewFrame[4].y = yt - 1;
  1246. X            ft = ShortFrame;
  1247. X            break;
  1248. X        }
  1249. X        default: {
  1250. X            break;
  1251. X        }
  1252. X    }
  1253. X    draw_frame(ft);
  1254. X}
  1255. X
  1256. XVOID FindWord()
  1257. X{
  1258. X      /* Must remove frame to be able to search for spaces */
  1259. X    WaitTOF();
  1260. X    erase_frame();
  1261. X    tl = mx;
  1262. X      /* Find a space to the left... */
  1263. X    while (!IsSpace(tl, my)) {
  1264. X        tl -= fw;
  1265. X        if (tl < minx) {
  1266. X            break;
  1267. X        }
  1268. X    }
  1269. X    tl += fw;
  1270. X    tr = mx;
  1271. X      /* ...and to the right */
  1272. X    while (!IsSpace(tr, my)) {
  1273. X        tr += fw;
  1274. X        if (tr + fw > maxx) {
  1275. X            break;
  1276. X        }
  1277. X    }
  1278. X    tr -= fw;
  1279. X    if (tr < tl) {
  1280. X        tl = xl;
  1281. X        tr = xr;
  1282. X    }
  1283. X}
  1284. X
  1285. X/* ChangeUnit cycles the unit of selection. The differents units
  1286. X   are: character, word and line.
  1287. X*/
  1288. X
  1289. XVOID ChangeUnit()
  1290. X{
  1291. X
  1292. X    switch (Unit) {
  1293. X        case UNIT_FRAME: {
  1294. X            Unit = UNIT_CHAR;
  1295. X            break;
  1296. X        }
  1297. X        case UNIT_CHAR: {
  1298. X            Unit = UNIT_WORD;
  1299. X            FindWord();
  1300. X            xl = tl;
  1301. X            xr = tr;
  1302. X            break;
  1303. X        }
  1304. X        case UNIT_WORD: {
  1305. X            Unit = UNIT_LINE;
  1306. X            xl = minx;
  1307. X            xr = maxx;
  1308. X            break;
  1309. X        }
  1310. X        case UNIT_LINE: {
  1311. X            Unit = UNIT_FRAME;
  1312. X            xl = xr = mx;
  1313. X            break;
  1314. X        }
  1315. X    }
  1316. X    if (SnapRsrc->CrawlPtrn == 0) {
  1317. X        Ptrn = Pattern[Unit];
  1318. X    }
  1319. X}
  1320. X
  1321. X/* ExtendSelection extends the current selection according to
  1322. X   the mouse position and the selected unit.
  1323. X   Note that ExtendSelection doesn't optimize moves that don't
  1324. X   make any difference. FIXME
  1325. X*/
  1326. X
  1327. XVOID ExtendSelection()
  1328. X{
  1329. X    /* Fix which row we're talking about */
  1330. X    if (closey == closetop) {       /* Find closest row */
  1331. X        yt = my;               /* change top row */
  1332. X    } else {
  1333. X        yb = my;               /* change bottom row */
  1334. X    }
  1335. X
  1336. X    /* Take care of left and right character pos */
  1337. X    switch (Unit) {
  1338. X        case UNIT_FRAME: {
  1339. X            if (closex == closeleft) {
  1340. X                xl = mx;
  1341. X            } else {
  1342. X                xr = mx;
  1343. X            }
  1344. X            break;
  1345. X        }
  1346. X        case UNIT_CHAR: {
  1347. X            if (yt == yb) {            /* One line */
  1348. X                if (closex == closeleft) {
  1349. X                    xl = mx;
  1350. X                } else {
  1351. X                    xr = mx;
  1352. X                }
  1353. X            } else {                    /* Multiple lines */
  1354. X                if (yt == my) {
  1355. X                    xl = mx;            /* At top - set left */
  1356. X                } else {
  1357. X                    xr = mx;            /* At bottom - set right */
  1358. X                }
  1359. X            }
  1360. X            break;
  1361. X        }
  1362. X        case UNIT_WORD: {
  1363. X            FindWord();                 /* Find the word */
  1364. X            if (yt == yb) {             /* One line */
  1365. X                if (closex == closeleft) {   /* Find closest char pos */
  1366. X                    xl = tl;
  1367. X                } else {
  1368. X                    xr = tr;
  1369. X                }
  1370. X            } else {                   /* Multiple lines */
  1371. X                if (yt == my) {        /* Where am I */
  1372. X                    xl = tl;           /* At top - set left */
  1373. X                } else {
  1374. X                    xr = tr;           /* At bottom - set right */
  1375. X                }
  1376. X            }
  1377. X            break;
  1378. X        }
  1379. X        case UNIT_LINE: {              /* Always full width */
  1380. X            break;
  1381. X        }
  1382. X    }
  1383. X    if (yt - fh == yb) {
  1384. X        yb += fh;
  1385. X    }
  1386. X    if (yt == yb && xl - fw == xr) {
  1387. X        xr += fw;
  1388. X    }
  1389. X    if (xr > maxx) {         /* Check for window bounds */
  1390. X        xr = maxx;
  1391. X    }
  1392. X    if (xl < minx) {         /* Check for window bounds */
  1393. X        xl = minx;
  1394. X    }
  1395. X    if (yb > maxy) {         /* Check for window bounds */
  1396. X        yb = maxy;
  1397. X    }
  1398. X}
  1399. X
  1400. X/* The actual character snapper. It actually works. :-) */
  1401. X
  1402. XWORD SnapChars()
  1403. X{
  1404. X    LONG width;
  1405. X    LONG height;
  1406. X    UBYTE *SnapSpace;
  1407. X    ULONG SnapSize;
  1408. X    ULONG counter;
  1409. X    REGISTER LONG x, y;
  1410. X
  1411. X      /* Check coordinates */
  1412. X    if (yt - fh == yb) {        /* No rows, shouldn't happen */
  1413. X        return 0;
  1414. X    }
  1415. X    if (yt == yb && xl - fw == xr) {     /* Nothing at all */
  1416. X        return 0;
  1417. X    }
  1418. X
  1419. X      /* Calculate stuff */
  1420. X    width = maxx - (minx + 1) + fw + fw;  /* Add one for a LF */
  1421. X    height = yb - yt + fh;
  1422. X    SnapSize = ((width / fw) + 1) * (height / fh);
  1423. X    counter = 0;
  1424. X
  1425. X      /* Initialize things */
  1426. X    InitRastPort(&MyRP);
  1427. X    InitBitMap(&MyBM, 1L, width, height);
  1428. X    MyRP.BitMap = &MyBM;
  1429. X    SnapSpace = AllocMem(SnapSize, MEMF_PUBLIC|MEMF_CLEAR);
  1430. X      /* Please insert more memory */
  1431. X    if (!SnapSpace) {
  1432. X        return 0;
  1433. X    }
  1434. X    MyBM.Planes[0] = AllocRaster(width, height);
  1435. X    if (!MyBM.Planes[0]) {
  1436. X        FreeMem(SnapSpace, SnapSize);
  1437. X        return 0;
  1438. X    }
  1439. X    IFlags = 0;
  1440. X      /* Make a local copy of the snapped chars */
  1441. X    ClipBlit(&rp, minx, yt, &MyRP, 0L, 0L, width, height, COPY);
  1442. X
  1443. X      /* Ok, now we've got a copy of the character data */
  1444. X      /* Now it's ok to mess with the layers again */
  1445. X    UnlockLayer(LockedLayer);
  1446. X
  1447. X      /* Clear our work area */
  1448. X    BltClear((char *)TempRaster, 32L, 0L);
  1449. X
  1450. X      /* Calculate bounds */
  1451. X    xl -= minx;
  1452. X    xr -= minx;
  1453. X    maxx -= minx;
  1454. X    minx = 0;
  1455. X    yb -= yt;
  1456. X    yt = 0;
  1457. X
  1458. X      /* Single line - needs to be handled separately */
  1459. X    if (yt == yb) { /* Ok, we've got one */
  1460. X
  1461. X          /* Read from left to right */
  1462. X        for (x = xl; x <= xr; x += fw, counter++) {
  1463. X            CopyChar(x, yt, COPY);
  1464. X            if ((SnapSpace[counter] = interpret(TempRaster)) == 255) {
  1465. X                SnapSpace[counter] = SnapRsrc->BadChar;  /* Unrecognized */
  1466. X            }
  1467. X        }
  1468. X        if (Unit == UNIT_LINE) {
  1469. X            while (counter && SnapSpace[counter-1] == ' ') {
  1470. X                counter--;
  1471. X            }
  1472. X        }
  1473. X    } else { /* Multiple lines */
  1474. X
  1475. X        if (Unit == UNIT_FRAME) {
  1476. X            minx = xl;
  1477. X            maxx = xr;
  1478. X        }
  1479. X
  1480. X          /* Read first line */
  1481. X        for (x = xl; x <= maxx; x += fw, counter++) {
  1482. X            CopyChar(x, yt, COPY);
  1483. X            if ((SnapSpace[counter] = interpret(TempRaster)) == 255) {
  1484. X                SnapSpace[counter] = SnapRsrc->BadChar;  /* Unrecognized */
  1485. X            }
  1486. X        }
  1487. X        if (Unit == UNIT_FRAME) {
  1488. X            SnapSpace[counter++] = 10;
  1489. X        } else {
  1490. X            SHORT endspace = (SnapSpace[counter-1] == ' ');
  1491. X              /* Remove trailing blanks */
  1492. X            while (counter && SnapSpace[counter-1] == ' ') {
  1493. X                counter--;
  1494. X            }
  1495. X            if (endspace || !(SnapRsrc->flags & JOINLONG)) {
  1496. X                SnapSpace[counter++] = 10;
  1497. X            }
  1498. X        }
  1499. X
  1500. X          /* If more than two rows - read full middle rows */
  1501. X        if (yt + fh != yb) {
  1502. X            for (y = yt + fh; y < yb; y += fh) {
  1503. X                for (x = minx; x <= maxx; x += fw, counter++) {
  1504. X                    CopyChar(x, y, COPY);
  1505. X                    if ((SnapSpace[counter] = interpret(TempRaster)) == 255) {
  1506. X                        SnapSpace[counter] = SnapRsrc->BadChar;  /* Unrecognized */
  1507. X                    }
  1508. X                }
  1509. X                if (Unit == UNIT_FRAME) {
  1510. X                    SnapSpace[counter++] = 10;
  1511. X                } else {
  1512. X                    SHORT endspace = (SnapSpace[counter-1] == ' ');
  1513. X                      /* Remove trailing blanks */
  1514. X                    while (counter && SnapSpace[counter-1] == ' ') {
  1515. X                        counter--;
  1516. X                    }
  1517. X                    if (endspace || !(SnapRsrc->flags & JOINLONG)) {
  1518. X                        SnapSpace[counter++] = 10;
  1519. X                    }
  1520. X                }
  1521. X            }
  1522. X        }
  1523. X
  1524. X          /* Read last line */
  1525. X        for (x = minx; x <= xr; x += fw, counter++) {
  1526. X            CopyChar(x, yb, COPY);
  1527. X            if ((SnapSpace[counter] = interpret(TempRaster)) == 255) {
  1528. X                SnapSpace[counter] = SnapRsrc->BadChar;  /* Unrecognized */
  1529. X            }
  1530. X        }
  1531. X        /* Remove trailing blanks */
  1532. X        while (counter && SnapSpace[counter-1] == ' ') {
  1533. X            counter--;
  1534. X        }
  1535. X    }
  1536. X    FreeRaster(MyBM.Planes[0], width, height);
  1537. X    SaveClip(SnapSpace, counter);
  1538. X    FreeMem(SnapSpace, SnapSize);
  1539. X    return 1;
  1540. X}
  1541. X
  1542. X
  1543. X/* HandleChars is the part of the Snap state machine that handles
  1544. X   snapping of characters. The selection is done in different
  1545. X   units: char, word, line.
  1546. X*/
  1547. X
  1548. XWORD HandleChars()
  1549. X{
  1550. X    LONG xoff, yoff;
  1551. X    LONG ox, oy;
  1552. X
  1553. X      /* Find out which screen we're working on */
  1554. X    theScreen = WhichScreen();
  1555. X
  1556. X      /* Oops, no screen? */
  1557. X    if (!theScreen) {
  1558. X        action = noaction;
  1559. X        return 0;
  1560. X    }
  1561. X
  1562. X      /* Ok, what window? */
  1563. X    window = WhichWindow(theScreen);
  1564. X
  1565. X      /* Oh dear, no window. */
  1566. X    if (!window) {
  1567. X        action = noaction;
  1568. X        return 0;
  1569. X    }
  1570. X
  1571. X      /* No messing with the layers while I think */
  1572. X    LockedLayer = window->WLayer;
  1573. X    LockLayer(0L, LockedLayer);
  1574. X
  1575. X      /* Don't want to wreck somebody's rastport */
  1576. X    CopyMem((char *)window->RPort, (char *)&rp, (LONG)sizeof(struct RastPort));
  1577. X
  1578. X      /* Or his picture */
  1579. X    SetDrMd(&rp, COMPLEMENT);
  1580. X    rp.Mask = SnapRsrc->FrameMask;
  1581. X
  1582. X      /* Find out what we're trying to read */
  1583. X    SetSnapFont(rp.Font);
  1584. X    if (FontWidth == -1) {
  1585. X        UnlockLayer(LockedLayer);
  1586. X        action = noaction;
  1587. X        return 0;
  1588. X    }
  1589. X
  1590. X    if (window->Flags & GIMMEZEROZERO) {
  1591. X        GZZ = 1;
  1592. X    } else {
  1593. X        GZZ = 0;
  1594. X    }
  1595. X    if (window->Flags & SUPER_BITMAP) {
  1596. X        SBM = 1;
  1597. X    } else {
  1598. X        SBM = 0;
  1599. X    }
  1600. X
  1601. X      /* Find a position */
  1602. X    xl = (GZZ ? window->GZZMouseX : window->MouseX)
  1603. X      + window->RPort->Layer->Scroll_X;
  1604. X    yt = (GZZ ? window->GZZMouseY : window->MouseY)
  1605. X      + window->RPort->Layer->Scroll_Y;
  1606. X
  1607. X    if (xl < 0) {
  1608. X        xl = 0;
  1609. X    }
  1610. X    if (yt < 0) {
  1611. X        yt = 0;
  1612. X    }
  1613. X
  1614. X      /* Check your position */
  1615. X    if (xl > (GZZ ? window->GZZWidth : window->Width) ||
  1616. X      yt > (GZZ ? window->GZZHeight : window->Height)) {
  1617. X        UnlockLayer(LockedLayer);
  1618. X        action = noaction;
  1619. X        return 0;
  1620. X    }
  1621. X    IFlags = 0;
  1622. X
  1623. X      /* Find out the offset for the clicked character, if any.
  1624. X      ** This is the part that makes it special. Simple, isn't it. Hah!
  1625. X      */
  1626. X    {
  1627. X        REGISTER struct CacheWindow *cw = GetCachedWindow(theScreen, window);
  1628. X
  1629. X        if (cw) {
  1630. X            xoff = - ((xl - cw->xoff) % cw->fw);
  1631. X            yoff = - ((yt - cw->yoff) % cw->fh);
  1632. X            BltClear((char *)TempRaster, 32L, 0L);
  1633. X            ClipBlit(&rp, xl + xoff, yt + yoff,
  1634. X              &TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, COPY);
  1635. X            WaitBlit();
  1636. X            if (interpret(TempRaster) != 255) {
  1637. X                goto found;
  1638. X            }
  1639. X        }
  1640. X          /* No cache or cache didn't match */
  1641. X        xl -= 7;
  1642. X        yt -= 7;
  1643. X        BltClear((char *)TempRaster, 32L, 0L);
  1644. X        xoff = 0;
  1645. X        while (xoff < (16 - FontWidth)) {
  1646. X            ClipBlit(&rp, xl + xoff, yt,
  1647. X              &TempRp, 0L, 0L, (LONG)FontWidth, 16L, COPY);
  1648. X            WaitBlit();
  1649. X            yoff = 0;
  1650. X            while (yoff < (16 - FontHeight)) {
  1651. X                if (interpret(&TempRaster[yoff]) != 255) {
  1652. X                    goto found;
  1653. X                }
  1654. X                ++yoff;
  1655. X            }
  1656. X            ++xoff;
  1657. X        }
  1658. X
  1659. X          /* No character found. Back off */
  1660. X        UnlockLayer(LockedLayer);
  1661. X        action = noaction;
  1662. X        return 0;
  1663. X
  1664. Xfound:
  1665. X          /* Ok, now we know where to look for chars.
  1666. X          ** xoff and yoff is character position within our 16x16 bitmap.
  1667. X          */
  1668. X        xl = xl + xoff;         /* Adjust x */
  1669. X        yt = yt + yoff;         /* Adjust y */
  1670. X
  1671. X        fw = FontWidth;
  1672. X        fh = FontHeight;
  1673. X
  1674. X        {
  1675. X            SHORT temp = fh;
  1676. X            while (temp <= fh + 1) {  /* Check for extra pixel row */
  1677. X                BltClear((char *)TempRaster, 32L, 0L);
  1678. X                ClipBlit(&rp, xl, yt + temp,
  1679. X                  &TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, COPY);
  1680. X                WaitBlit();
  1681. X                if (interpret(TempRaster) != 255) {
  1682. X                    fh = temp;
  1683. X                    break;
  1684. X                }
  1685. X                ++temp;
  1686. X            }
  1687. X        }
  1688. X
  1689. X          /* Find out offsets within the window */
  1690. X        xoff = xl % fw;
  1691. X        yoff = yt % fh;
  1692. X
  1693. X        if (cw) {
  1694. X            cw->xoff = xoff;
  1695. X            cw->yoff = yoff;
  1696. X            cw->fw = fw;
  1697. X            cw->fh = fh;
  1698. X        } else {
  1699. X            CacheWindow(window, xoff, yoff, fw, fh);
  1700. X        }
  1701. X    }
  1702. X
  1703. X      /* Set bounds */
  1704. X    minx = xoff;
  1705. X    maxx = minx +
  1706. X      (((GZZ ?
  1707. X        window->GZZWidth :
  1708. X        window->Width - window->BorderRight
  1709. X          /* Hack for borderless conman windows */
  1710. X        + (window->Flags & BORDERLESS && window->Flags & WINDOWSIZING ? 14 : 0))
  1711. X      - minx - fw) / fw) * fw;
  1712. X    maxy = ((GZZ ? window->GZZHeight : window->Height) / fh) * fh;
  1713. X
  1714. X      /* Check bounds */
  1715. X    if (xl > maxx) {
  1716. X        UnlockLayer(LockedLayer);
  1717. X        action = noaction;
  1718. X        return 0;
  1719. X    }
  1720. X      /* Set box dimensions */
  1721. X    xr = xl;
  1722. X    yb = yt;
  1723. X    ox = xr;
  1724. X    oy = yt;
  1725. X
  1726. X      /* Select unit while starting */
  1727. X    starting = 1;
  1728. X
  1729. X      /* Starting unit is character or frame */
  1730. X    Unit = SnapRsrc->StartUnit;
  1731. X    Ptrn = (SnapRsrc->CrawlPtrn ? SnapRsrc->CrawlPtrn : Pattern[Unit]);
  1732. X    OFType = 0L;
  1733. X    update_frame();
  1734. X
  1735. X      /* Get the state machine running */
  1736. X    FOREVER {
  1737. X          /* Wait for something to happen */
  1738. X        REGISTER LONGBITS sig =
  1739. X          Wait(movesignal|cancelsignal|donesignal|clicksignal|timersignal);
  1740. X
  1741. X        if ((sig & timersignal) && (SnapRsrc->CrawlPtrn != 0xffff)) {
  1742. X            crawl_frame(0L);
  1743. X        }
  1744. X
  1745. X        mx = (LONG)(GZZ ? window->GZZMouseX : window->MouseX)
  1746. X          + window->RPort->Layer->Scroll_X;
  1747. X        if (mx < 0) {
  1748. X            mx = 0;
  1749. X        }
  1750. X          /* Calculate which edge is closest */
  1751. X        if ((mx - xl) < (xr - mx)) {
  1752. X            closex = closeleft;
  1753. X        } else {
  1754. X            closex = closeright;
  1755. X        }
  1756. X          /* Only interested in real char pos */
  1757. X        mx = mx - ((mx - xoff) % fw);
  1758. X
  1759. X        my = (LONG)(GZZ ? window->GZZMouseY : window->MouseY)
  1760. X          + window->RPort->Layer->Scroll_Y;
  1761. X        if (my < 0) {
  1762. X            my = 0;
  1763. X        }
  1764. X          /* Calculate which row is closest */
  1765. X        if ((my - yt) < (yb - my)) {
  1766. X            closey = closetop;
  1767. X        } else {
  1768. X            closey = closebottom;
  1769. X        }
  1770. X        my = my - ((my - yoff) % fh);
  1771. X
  1772. X          /* Hey, it moves! It's alive!! */
  1773. X        if ((sig & movesignal) && (action == snaptext)) {
  1774. X            if (mx != ox || my != oy) {  /* Something's happened */
  1775. X                ExtendSelection();
  1776. X                update_frame();
  1777. X                starting = 0;
  1778. X                ox = mx;
  1779. X                oy = my;
  1780. X                sig &= ~clicksignal;
  1781. X            }
  1782. X        }
  1783. X
  1784. X          /* Ok, forget it... */
  1785. X        if (sig & cancelsignal) {
  1786. X            erase_frame();
  1787. X            UnlockLayer(LockedLayer);
  1788. X            return 0;
  1789. X        }
  1790. X
  1791. X          /* Click */
  1792. X        if ((sig & clicksignal) && (action == snaptext)) {
  1793. X              /* Selecting unit */
  1794. X            if (starting) {
  1795. X                if (mx == ox && my == oy) {
  1796. X                    ChangeUnit();
  1797. X                    if (Unit == UNIT_CHAR) {
  1798. X                        ChangeUnit();
  1799. X                    }
  1800. X                    update_frame();
  1801. X                } else if (Unit == UNIT_FRAME) {
  1802. X                    ChangeUnit();
  1803. X                    update_frame();
  1804. X                }
  1805. X            }
  1806. X            if (mx != ox || my != oy) { /* Click in a new place */
  1807. X                ExtendSelection();
  1808. X                update_frame();
  1809. X                starting = 0;
  1810. X                ox = mx;
  1811. X                oy = my;
  1812. X            }
  1813. X        }
  1814. X
  1815. X          /* Finished */
  1816. X        if (sig & donesignal) {
  1817. X            erase_frame();
  1818. X            return SnapChars();
  1819. X        }
  1820. X    }
  1821. X}
  1822. X
  1823. END_OF_FILE
  1824. if test 21526 -ne `wc -c <'source/snapchars.c'`; then
  1825.     echo shar: \"'source/snapchars.c'\" unpacked with wrong size!
  1826. fi
  1827. # end of 'source/snapchars.c'
  1828. fi
  1829. echo shar: End of archive 3 \(of 4\).
  1830. cp /dev/null ark3isdone
  1831. MISSING=""
  1832. for I in 1 2 3 4 ; do
  1833.     if test ! -f ark${I}isdone ; then
  1834.     MISSING="${MISSING} ${I}"
  1835.     fi
  1836. done
  1837. if test "${MISSING}" = "" ; then
  1838.     echo You have unpacked all 4 archives.
  1839.     rm -f ark[1-9]isdone
  1840. else
  1841.     echo You still need to unpack the following archives:
  1842.     echo "        " ${MISSING}
  1843. fi
  1844. ##  End of shell archive.
  1845. exit 0
  1846. -- 
  1847. Mail submissions (sources or binaries) to <amiga@cs.odu.edu>.
  1848. Mail comments to the moderator at <amiga-request@cs.odu.edu>.
  1849. Post requests for sources, and general dicussion to comp.sys.amiga.
  1850.